/*
 * Copyright 2017 Zhihu Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xiaoyu.media.matisse.internal.ui

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.annotation.CallSuper
import androidx.viewpager.widget.ViewPager
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.cardview.widget.CardView
import android.view.View
import android.view.WindowManager
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.FrameLayout
import android.widget.TextView

import com.xiaoyu.media.matisse.internal.entity.IncapableCause
import com.xiaoyu.media.matisse.internal.entity.Item
import com.xiaoyu.media.matisse.internal.entity.SelectionSpec
import com.xiaoyu.media.matisse.internal.model.SelectedItemCollection
import com.xiaoyu.media.matisse.internal.ui.adapter.PreviewPagerAdapter
import com.xiaoyu.media.matisse.internal.utils.PhotoMetadataUtils
import com.xiaoyu.media.matisse.internal.utils.Platform
import com.xiaoyu.media.matisse.listener.OnFragmentInteractionListener
import com.xiaoyu.media.matisse.ui.MatisseRadioButton
import com.xiaoyu.media.R

abstract class BasePreviewActivity : AppCompatActivity(), View.OnClickListener, ViewPager.OnPageChangeListener, OnFragmentInteractionListener, CompoundButton.OnCheckedChangeListener {

    protected val mSelectedCollection = SelectedItemCollection(this)
    protected var mPreviewItem: Item? = null
    protected var mSpec: SelectionSpec = SelectionSpec.instance
    protected var mPager: ViewPager? = null

    protected var mAdapter: PreviewPagerAdapter? = null

    protected var mCheckView: CheckBox? = null
    protected var mButtonBack: TextView? = null
    protected var mButtonApply: TextView? = null
    protected var mButtonOriginal: MatisseRadioButton? = null

    protected var mPreviousPos = -1

    protected var mOriginalEnable: Boolean = false
    protected var mOriginalChecked: Boolean = false

    private var mBottomToolbar: CardView? = null
    private var mTopToolbar: FrameLayout? = null
    private var mIsToolbarHide = false

    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme(SelectionSpec.instance.themeId)
        super.onCreate(savedInstanceState)
        if (!SelectionSpec.instance.hasInited) {
            setResult(Activity.RESULT_CANCELED)
            finish()
            return
        }
        setContentView(R.layout.matisse_activity_media_preview)
        if (Platform.hasKitKat()) {
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
        }

        mSpec = SelectionSpec.instance
        if (mSpec.needOrientationRestriction()) {
            requestedOrientation = mSpec.orientation
        }

        initView()
        initAdapter()
        initBind()
        initData(savedInstanceState)
        updateApplyButton()
        updateOriginalButton()
    }

    private fun updateOriginalButton() {
        mButtonOriginal?.visibility = if (mOriginalEnable) View.VISIBLE else View.GONE
        mButtonOriginal?.isChecked = mOriginalChecked
    }

    override fun onSaveInstanceState(outState: Bundle) {
        mSelectedCollection.onSaveInstanceState(outState)
        outState.putBoolean(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
        outState.putBoolean(CHECK_STATE, mOriginalChecked)
        super.onSaveInstanceState(outState)
    }

    override fun onBackPressed() {
        sendBackResult(false)
        super.onBackPressed()
    }

    override fun onClick(v: View) {
        when (v.id) {
            R.id.button_back -> {
                onBackPressed()
            }
            R.id.button_apply -> {
                sendBackResult(true)
                finish()
            }
        }
    }

    override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
        mOriginalChecked = isChecked
    }

    override fun onClick() {
        if (!mSpec.autoHideToobar) {
            return
        }

        if (mIsToolbarHide) {
            mTopToolbar?.measuredHeight?.toFloat()?.let {
                mTopToolbar?.animate()
                        ?.setInterpolator(FastOutSlowInInterpolator())
                        ?.translationYBy(it)
                        ?.start()
            }
            mBottomToolbar?.measuredHeight?.toFloat()?.let {
                mBottomToolbar?.animate()
                        ?.setInterpolator(FastOutSlowInInterpolator())
                        ?.translationYBy(-it)
                        ?.start()
            }
        } else {
            mTopToolbar?.measuredHeight?.toFloat()?.let {
                mTopToolbar?.animate()
                        ?.setInterpolator(FastOutSlowInInterpolator())
                        ?.translationYBy(-it)
                        ?.start()
            }
            mBottomToolbar?.measuredHeight?.toFloat()?.let {
                mBottomToolbar?.animate()
                        ?.setInterpolator(FastOutSlowInInterpolator())
                        ?.translationYBy(it)
                        ?.start()
            }
        }

        mIsToolbarHide = !mIsToolbarHide
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

    override fun onPageSelected(position: Int) {
        val adapter = mPager?.adapter as PreviewPagerAdapter?
        if (mPreviousPos != -1 && mPreviousPos != position) {
            (mPager?.let { adapter?.instantiateItem(it, mPreviousPos) } as PreviewItemFragment).resetView()

            val item = adapter?.getMediaItem(position)
            if (mSpec.countable) {
                val checkedNum = item?.let { mSelectedCollection.checkedNumOf(it) } ?: 0
                if (checkedNum > 0) {
                    mCheckView?.isEnabled = true
                } else {
                    mCheckView?.isEnabled = !mSelectedCollection.maxSelectableReached()
                }
            } else {
                val checked = item?.let { mSelectedCollection.isSelected(it) } ?: false
                mCheckView?.isChecked = checked
                if (checked) {
                    mCheckView?.isEnabled = true
                } else {
                    mCheckView?.isEnabled = !mSelectedCollection.maxSelectableReached()
                }
            }
        }
        mPreviousPos = position
    }

    override fun onPageScrollStateChanged(state: Int) {
    }

    private fun initView() {
        mButtonBack = findViewById(R.id.button_back)
        mButtonApply = findViewById(R.id.button_apply)
        mButtonOriginal = findViewById(R.id.button_original)
        mPager = findViewById(R.id.pager)
        mCheckView = findViewById(R.id.check_view)
        mBottomToolbar = findViewById(R.id.bottom_toolbar)
        mTopToolbar = findViewById(R.id.top_toolbar)
    }

    private fun initAdapter() {
        mAdapter = PreviewPagerAdapter(supportFragmentManager, null)
        mPager?.adapter = mAdapter
    }

    private fun initBind() {
        mButtonBack?.setOnClickListener(this)
        mButtonApply?.setOnClickListener(this)
        mButtonOriginal?.setOnCheckedChangeListener(this)
        mPager?.addOnPageChangeListener(this)
        mCheckView?.setOnClickListener {
            val item = mAdapter?.getMediaItem(mPager?.currentItem ?: 0)
            item?.let {
                if (mSelectedCollection.isSelected(it)) {
                    mSelectedCollection.remove(it)
                    mCheckView?.isChecked = false
                } else {
                    if (assertAddSelection(it)) {
                        mSelectedCollection.add(it)
                        mCheckView?.isChecked = true
                    }
                }
            }
            updateApplyButton()

            mSpec.onSelectedListener?.onSelected(mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString())
        }
    }

    @CallSuper
    protected open fun initData(savedInstanceState: Bundle?) {
        mOriginalEnable = if (savedInstanceState == null) {
            mSelectedCollection.onCreate(intent.getBundleExtra(EXTRA_DEFAULT_BUNDLE))
            intent.getBooleanExtra(EXTRA_RESULT_ORIGINAL_ENABLE, false)
        } else {
            mSelectedCollection.onCreate(savedInstanceState)
            savedInstanceState.getBoolean(EXTRA_RESULT_ORIGINAL_ENABLE)
        }
        mOriginalChecked = if (savedInstanceState == null) {
            mSelectedCollection.onCreate(intent.getBundleExtra(EXTRA_DEFAULT_BUNDLE))
            intent.getBooleanExtra(CHECK_STATE, false)
        } else {
            mSelectedCollection.onCreate(savedInstanceState)
            savedInstanceState.getBoolean(CHECK_STATE)
        }
    }

    private fun updateApplyButton() {
        val selectedCount = mSelectedCollection.count()
        if (selectedCount == 0) {
            mButtonApply?.setText(R.string.button_sure_default)
            mButtonApply?.isEnabled = mPreviewItem != null
        } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) {
            mButtonApply?.setText(R.string.button_sure_default)
            mButtonApply?.isEnabled = true
        } else {
            mButtonApply?.isEnabled = true
            mButtonApply?.text = getString(R.string.button_sure, selectedCount)
        }
    }

    private fun countOverMaxSize(): Int {
        var count = 0
        val selectedCount = mSelectedCollection.count()
        for (i in 0 until selectedCount) {
            val item = mSelectedCollection.asList()[i]
            if (item.isImage) {
                val size = PhotoMetadataUtils.getSizeInMB(item.size)
                if (size > mSpec.originalMaxSize) {
                    count++
                }
            }
        }
        return count
    }

    private fun sendBackResult(apply: Boolean) {
        tryAddPreviewItemToSelectedCollection(apply)
        val intent = Intent()
        intent.putExtra(EXTRA_RESULT_BUNDLE, mSelectedCollection.dataWithBundle)
        intent.putExtra(EXTRA_RESULT_APPLY, apply)
        intent.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
        intent.putExtra(CHECK_STATE, mOriginalChecked)
        setResult(Activity.RESULT_OK, intent)
    }

    private fun tryAddPreviewItemToSelectedCollection(apply: Boolean) {
        if (!apply) {
            return
        }
        if (mSelectedCollection.isEmpty) {
            mPreviewItem?.let {
                mSelectedCollection.add(it)
            }
        }
    }

    private fun assertAddSelection(item: Item): Boolean {
        val cause = mSelectedCollection.isAcceptable(item)
        IncapableCause.handleCause(this, cause)
        return cause == null
    }

    companion object {

        const val EXTRA_DEFAULT_BUNDLE = "extra_default_bundle"
        const val EXTRA_RESULT_BUNDLE = "extra_result_bundle"
        const val EXTRA_RESULT_APPLY = "extra_result_apply"
        const val EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable"
        const val CHECK_STATE = "checkState"

        init {
            AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
        }
    }
}
